package com.bocloud.cmp.driver.providers.os;

import org.openstack4j.api.OSClient;
import org.openstack4j.api.OSClient.OSClientV2;
import org.openstack4j.api.OSClient.OSClientV3;
import org.openstack4j.model.common.Identifier;
import org.openstack4j.openstack.OSFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.bocloud.cmp.driver.providers.Driver;
import com.bocloud.common.model.Result;

/**
 * Openstack驱动客户端
 * 
 * @author dmw
 *
 */
public class OSDriver implements Driver {

	private static final Logger logger = LoggerFactory.getLogger(OSDriver.class);
	private String endpoint;// 任务路径
	private String username;// 管理员账号
	private String password;// 管理员密码
	private String tenant;// 租户名称
	private String domain;// 域名称
	private String project;// 工程名
	private Version version;// KeyStone的认证API版本
	private OSClientV2 client2;
	private OSClientV3 client3;
	private OSClient<?> client;
	private boolean accessable;
	private String error; // 错误信息

	public enum Version {
		V2, V3;
	}

	@Override
	public boolean accessable() {
		return this.accessable;
	}

	public OSDriver() {
		super();
	}

	public OSDriver(String endpoint, String username, String password, String tenant, String domain, String project,
			Version version) {
		super();
		this.endpoint = endpoint;
		this.username = username;
		this.password = password;
		this.tenant = tenant;
		this.domain = domain;
		this.project = project;
		this.version = version;
		init();
	}

	/**
	 * 初始化客户端连接
	 */
	private void init() {
		Result result = paramCheck();
		if (result.isFailed()) {// 基本的参数校验不通过，即用户名，密码或者认证路径为空
			this.accessable = false;
			logger.error("Driver init error : {}", result.getMessage());
			this.error = result.getMessage();
			return;
		}
		decideVersion();// 确定认证版本
		if (logger.isDebugEnabled()) {
			logger.info("Keystone Version:{}", this.version);
		}
		try {
			switch (this.version) {
			case V2:
				buildV2();
				break;
			case V3:
				buildV3();
				break;
			default:
				logger.warn("Unsupported Version! Use V2 version to build!");
				buildV2();
				break;
			}
		} catch (Exception e) {
			logger.error("OSDriver Init Error:", e);
			this.accessable = false;
			this.error = e.getMessage();
		}
	}

	/**
	 * 基本参数信息认证，即确保认证路径，认证账号和认证密码为非空
	 * 
	 * @return
	 */
	private Result paramCheck() {
		if (StringUtils.isEmpty(this.endpoint)) {
			return new Result(false, "Endpoint is Empty!");
		}
		if (StringUtils.isEmpty(this.username)) {
			return new Result(false, "Username is Empty!");
		}
		if (StringUtils.isEmpty(this.password)) {
			return new Result(false, "Password is Empty!");
		}
		if (null == this.version) {
			this.version = Version.V2;
		}
		switch (this.version) {
		case V3:
			if (StringUtils.isEmpty(this.project)) {
				return new Result(false, "Project is Empty!");
			}
			break;
		case V2:
			if (StringUtils.isEmpty(this.tenant)) {
				return new Result(false, "Tenant is Empty!");
			}
			break;
		default:
			logger.warn("Uknown Version use V2 to build");
			if (StringUtils.isEmpty(this.tenant)) {
				return new Result(false, "Tenant is Empty!");
			}
			break;
		}

		return new Result(true, "success");
	}

	private void buildEndpoint(String version) {
		if (this.endpoint.endsWith("/")) {
			this.endpoint = this.endpoint + version + "/";
		} else {
			this.endpoint = this.endpoint + "/" + version + "/";
		}
	}

	/**
	 * 确定版本信息，根据传入的版本参数或者认证路径endpoint来确定
	 * 
	 */
	private void decideVersion() {
		this.endpoint = this.endpoint.trim();
		if (null == this.version) {
			this.version = Version.V2;
		}
		switch (this.version) {
		case V3:
			buildEndpoint("v3");
			break;
		case V2:
			buildEndpoint("v2.0");
			break;
		default:
			logger.warn("Uknown Version use V2 to build");
			buildEndpoint("v2.0");
			break;
		}
	}

	/**
	 * 构建V2版本的客户端
	 */
	private void buildV2() {
		this.client2 = OSFactory.builderV2().endpoint(this.endpoint).credentials(this.username, this.password)
				.tenantName(this.tenant).authenticate();
		this.client = client2;
		this.accessable = true;
	}

	/**
	 * 构建V3版本的客户端
	 */
	private void buildV3() {
		if (StringUtils.isEmpty(this.domain)) {
			this.accessable = false;
			this.error = "Driver init error : Domain is empty!";
			logger.error(error);
			return;
		}
		Identifier domainIdentifier = Identifier.byName(this.domain);
		if (StringUtils.isEmpty(project)) {
			this.client3 = OSFactory.builderV3().endpoint(this.endpoint)
					.credentials(this.username, this.password, domainIdentifier).authenticate();
		} else {
			this.client3 = OSFactory.builderV3().endpoint(this.endpoint)
					.credentials(this.username, this.password, domainIdentifier)
					.scopeToProject(Identifier.byName(this.project), Identifier.byName(this.domain)).authenticate();
		}
		this.client = this.client3;
		this.accessable = true;
	}

	public String getEndpoint() {
		return endpoint;
	}

	public void setEndpoint(String endpoint) {
		this.endpoint = endpoint;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getTenant() {
		return tenant;
	}

	public void setTenant(String tenant) {
		this.tenant = tenant;
	}

	public String getDomain() {
		return domain;
	}

	public void setDomain(String domain) {
		this.domain = domain;
	}

	public String getProject() {
		return project;
	}

	public void setProject(String project) {
		this.project = project;
	}

	public Version getVersion() {
		return version;
	}

	public void setVersion(Version version) {
		this.version = version;
	}

	public OSClientV2 getClient2() {
		return client2;
	}

	public OSClientV3 getClient3() {
		return client3;
	}

	public boolean isAccessable() {
		return accessable;
	}

	public OSClient<?> getClient() {
		return client;
	}

	public String getError() {
		return error;
	}

}
